package ao.ai.classify.decision;

import ao.ai.classify.decision.impl.classification.raw.Prediction;
import ao.ai.classify.decision.impl.input.raw.example.Context;
import ao.ai.classify.decision.impl.input.raw.example.ContextImpl;
import ao.ai.classify.decision.impl.input.raw.example.Datum;
import ao.ai.classify.decision.impl.input.raw.example.LearningSet;
import ao.ai.classify.decision.impl.model.raw.Classifier;
import ao.ai.classify.decision.impl.model.raw.ClassifierImpl;
import ao.ai.classify.decision.impl.tree.GeneralTreeLearner;
import ao.ai.model.common.data.NumList;
import ao.ai.model.ml.classify.example.BinClassified;
import ao.ai.model.ml.classify.hypothesis.classification.bin.BinProbClassification;
import ao.ai.model.ml.classify.hypothesis.classification.bin.impl.BinProbClassImpl;
import ao.ai.model.ml.classify.hypothesis.classifier.num.NumBinProbClassifier;
import ao.ai.model.ml.classify.learner.num.NumBinProbClassLeaner;
import com.google.common.collect.Iterables;

import java.util.LinkedList;
import java.util.List;

/**
 * User: alex
 * Date: 25-Apr-2010
 * Time: 6:51:54 PM
 */
public class MinInfoBinClassifier
        implements NumBinProbClassLeaner//BinProbClassLearner<NumList>
{
    //-------------------------------------------------------------------------
    @Override
    public NumBinProbClassifier learn(
            List<? extends BinClassified<NumList>> data)
    {
        assert data != null && ! data.isEmpty();

        final BinClassified<NumList>
            arbitraryExample = Iterables.get(data, 0);

        final LearningSet examples = new LearningSet();
        final Classifier learner  =
                new ClassifierImpl(
                        new GeneralTreeLearner());

        for (BinClassified<NumList> example : data)
        {
            examples.add(
                    function(
                            example.classification().best().getBin(),
                            example.input().getDoubles()));
        }

        learner.set( examples );
        
        return new NumBinProbClassifier() {
            @Override
            public BinProbClassification classify(NumList input)
            {
                Prediction guess = learner.classify(
                        context( input.getDoubles() ));
                return new BinProbClassImpl(
                        guess.probabilityOf(
                                new Datum(true)));
            }
        };
    }


    //-------------------------------------------------------------------------
    private ao.ai.classify.decision.impl.input.raw.example.Example
            function(boolean   isPositive,
                     double... input)
    {
        return context(input).withTarget(
                new Datum(isPositive));
    }

    private Context context(double... vars)
    {
        List<Datum> varAttributes = new LinkedList<Datum>();
        int         type          = 0;
        for (double var : vars)
        {
            varAttributes.add(
                    new Datum(String.valueOf(type++), var));
        }
        return new ContextImpl(varAttributes);
    }
}
